package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tencentcloudapi.common.AbstractModel;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.vod.v20180717.VodClient;
import com.tencentcloudapi.vod.v20180717.models.DeleteMediaRequest;
import com.tencentcloudapi.vod.v20180717.models.DeleteMediaResponse;
import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest;
import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodClient vodClient;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Override
    public List<AlbumInfo> findUserAllAlbumList() {
        Long userId = AuthContextHolder.getUserId();
        LambdaQueryWrapper<AlbumInfo> lambdaQueryWrapper = new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId);
        lambdaQueryWrapper.select(AlbumInfo::getId, AlbumInfo::getAlbumTitle);
        lambdaQueryWrapper.orderByDesc(AlbumInfo::getId);
        lambdaQueryWrapper.last(" limit 10 ");
        List<AlbumInfo> trackInfos = albumInfoMapper.selectList(lambdaQueryWrapper);
        return trackInfos;
    }

    /**
     * @Description 保存声音信息的操作
     * 1.将声音信息添加到track_info表中
     * 2.将声音统计信息添加到统计表中
     * 3.将专辑表中的一个字段做更新操作
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        // 1.更新专辑表中的字段信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        albumInfoMapper.update(null, new LambdaUpdateWrapper<AlbumInfo>()
                .eq(AlbumInfo::getId, trackInfoVo.getAlbumId())
                .set(AlbumInfo::getIncludeTrackCount, albumInfo.getIncludeTrackCount() + 1));

        // 2.将声音信息添加到声音表中
        TrackInfo trackInfo = getTrackInfo(trackInfoVo, albumInfo);
        trackInfoMapper.insert(trackInfo);

        // 3.将声音统计信息添加到声音统计表中
        insertTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY);
        insertTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT);
        insertTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE);
        insertTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT);
    }

    @Override
    public Page<TrackListVo> findUserTrackPage(Page<TrackListVo> page, TrackInfoQuery trackInfoQuery) {
        if (Objects.isNull(trackInfoQuery.getUserId())) {
            trackInfoQuery.setUserId(AuthContextHolder.getUserId());
        }
        return trackInfoMapper.selectUserTrackPage(page, trackInfoQuery);
    }

    /**
     * @Description 更新声音信息
     * 1.更新声音信息表
     * 2.判断是否修改了声音(通过判断声音id是否修改)
     * 3.如果修改了声音信息,那么需要重新查询声音的媒体信息,并且删除之前存储在云点播的声音信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackInfo(TrackInfo trackInfo) {
        TrackInfo trackInfoFromDB = trackInfoMapper.selectById(trackInfo.getId());
        if (!trackInfo.getMediaFileId().equals(trackInfoFromDB.getMediaFileId())) {
            // 声音发生了修改,重新查询云点播的声音媒体信息
            TrackInfo trackVodInfo = getTrackVodInfo(trackInfo.getMediaFileId());
            trackInfo.setMediaDuration(trackVodInfo.getMediaDuration());
            trackInfo.setMediaType(trackVodInfo.getMediaType());
            trackInfo.setMediaSize(trackVodInfo.getMediaSize());
        }
        // 删除之前存储在云点播中的声音信息
        deleteTrackMedia(trackInfoFromDB.getMediaFileId());
        // 最后更新声音信息表
        trackInfoMapper.updateById(trackInfo);
    }

    /**
     * @Description 删除声音信息
     * 1.删除声音信息表(更新声音表中对应专辑下其他声音的排序规则)
     * 2.删除声音统计表
     * 3.删除云点播中存储的声音
     * 4.更新专辑表中的一个属性
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long trackId) {
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

        // 删除声音信息表
        trackInfoMapper.deleteById(trackId);
        // 更新声音表中的排序规则,保证排序规则是连续的
        // update track_info set order_num = order_num - 1 where order_num > ? and album_id = ?
        // 这条SQL不能通过mybatis-plus提供的功能实现,所以需要自己实现
        trackInfoMapper.updateTrackOrderNum(trackInfo.getAlbumId(), trackInfo.getOrderNum());

        // 删除声音统计表
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        // 删除云点播中存储的声音信息
        deleteTrackMedia(trackInfo.getMediaFileId());

        // 删除专辑表中包含的声音字段
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        albumInfoMapper.update(null, new LambdaUpdateWrapper<AlbumInfo>()
                .eq(AlbumInfo::getId, trackInfo.getAlbumId())
                .set(AlbumInfo::getIncludeTrackCount, albumInfo.getIncludeTrackCount() - 1));
    }

    /**
     * @Description 从腾讯云点播中删除 指定的声音信息
     */
    private void deleteTrackMedia(String mediaFileId) {
        try{
            log.info("deleteTrackMedia mediaFileId is {}", mediaFileId);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DeleteMediaRequest req = new DeleteMediaRequest();
            req.setFileId(mediaFileId);
            // 返回的resp是一个DeleteMediaResponse的实例，与请求对象对应
            DeleteMediaResponse resp = vodClient.DeleteMedia(req);
            // 输出json格式的字符串回包
            log.info("deleteTrackMedia resp {}", AbstractModel.toJsonString(resp));
        } catch (TencentCloudSDKException e) {
            log.error("deleteTrackMedia error {}", e.toString());
            throw new RuntimeException(e);
        }
    }

    private void insertTrackStat(Long trackId, String statType) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(0);
        trackStatMapper.insert(trackStat);
    }

    private TrackInfo getTrackInfo(TrackInfoVo trackInfoVo, AlbumInfo albumInfo) {
        TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
        // 设置声音的媒体信息(时长\媒体类型\音频大小等数据) 需要调用云点播的接口进行查询
        TrackInfo mediaTrackInfoFromCloud = getTrackVodInfo(trackInfoVo.getMediaFileId());
        trackInfo.setMediaFileId(trackInfoVo.getMediaFileId());
        trackInfo.setMediaUrl(trackInfoVo.getMediaUrl());
        trackInfo.setMediaDuration(mediaTrackInfoFromCloud.getMediaDuration());
        trackInfo.setMediaSize(mediaTrackInfoFromCloud.getMediaSize());
        trackInfo.setMediaType(mediaTrackInfoFromCloud.getMediaType());

        trackInfo.setUserId(AuthContextHolder.getUserId());
        // 设置声音的排序规则
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
        // 设置声音的来源
        trackInfo.setSource(SystemConstant.TRACK_SOURCE_UPLOAD);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
        return trackInfo;
    }

    /**
     * @Description 获取媒体详细信息,需要调用云点播的接口进行查询,返回封装后的数据
     */
    private TrackInfo getTrackVodInfo(String fileId) {
        TrackInfo trackInfo = new TrackInfo();
        try{
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DescribeMediaInfosRequest req = new DescribeMediaInfosRequest();
            String[] fileIds1 = {fileId};
            req.setFileIds(fileIds1);

            // 返回的resp是一个DescribeMediaInfosResponse的实例，与请求对象对应
            DescribeMediaInfosResponse resp = vodClient.DescribeMediaInfos(req);
            // 输出json格式的字符串回包
            log.info("getTrackVodInfo resp {}", AbstractModel.toJsonString(resp));

            if (Objects.nonNull(resp) && Objects.nonNull(resp.getMediaInfoSet()) && Objects.nonNull(resp.getMediaInfoSet()[0])) {
                trackInfo.setMediaDuration(new BigDecimal(resp.getMediaInfoSet()[0].getMetaData().getDuration()));
                trackInfo.setMediaType(resp.getMediaInfoSet()[0].getBasicInfo().getType());
                trackInfo.setMediaSize(resp.getMediaInfoSet()[0].getMetaData().getSize());
            }
        } catch (TencentCloudSDKException e) {
            log.error("getTrackVodInfo error", e);
            throw new RuntimeException(e.getMessage());
        }
        return trackInfo;
    }
}
